﻿timer = {
  eventstack = list.new()
}

ringbuffer = {}
ringbuffer.ring = {}
ringbuffer.index = 0
ringbuffer.insert = function(self, item, compare)

end

ringbuffer.remove = function(self, itemorindex)

end

ringbuffer.next = function(self)
  self.index = self.index + 1
  if self.index > #self.ring then
    self.index = 0
  end
  return self.ring[self.index] 
end

ringbuffer.step = function(self, predicate)
  local next = 0
  while true do
    local = self.next()
    if predicate() then
    
    else
      return
    end
  end  
end

work = function (data)
  print(data,"lala")
  return true
end

thread = function (name, worker, data, timeslice, critical)
  local t = {}
  t.name = name
  t.worker = worker
  t.data = data or {}
  t.timeslice = timeslice
  t.critical = critical
  t.thread = coroutine.create(
  function(t)
    local ok = true
    while true do
      local complete = false
      local critical = t.critical --if critical we work till we finish,
                                --and alert if we overshoot our timeslice
                                --else we yield upon time slice is up
      local timeout = os.clock() + t.timeslice
      complete = false      
      while not(complete == true) do
        if (timeout < os.clock()) then
          if critical then
            print(t.name, "'s work might be overloaded")            
          else
            break
          end  
        end
        ok, complete = pcall(t.worker,t)
        if ok == false then
          --work screwed up so log a message
          print(t.name,"'s worker caused an error in its protected enviroment")
        end 
      end
      t = coroutine.yield(complete)
    end
  end
  )
  t.__call = function (self)
    coroutine.resume(self.thread,self)
  end
  setmetatable(t,t)
  return t
end

t = thread("test",work,"data",0.02,false)

createtask = function(name,t)
   local task = {
     complete = false,
     __name = name,
     subtasks = list.new(),
     addsubtask = function(self,subtask)
       self.subtasks:pushleft(subtask)
     end,
     removesubtask = function(self,subtask)
       self.subtasks:popleft()
     end,
     check = function(self,dt)
       if self.complete == true then
         print(self.__name.." Task Finished")
         return "finished","continue"       
       end
       if self.subtasks:length() == 0 then
         self.complete = true
         print(self.__name.." Task Block Siblings")
         return "inprogress","blocksiblings"
       else
         print(self.__name.." Task Continue")
         return "inprogress","continue"
       end
     end,
     act = function(self,dt)
       local finished, state = "finished", "inprogress"
       -- If all subtasks are finished, and we are finished finished is true
       local st
       for st in entries(self.subtasks) do
         finished,state = st:act(dt)
         if finished == "finished" then
           self:removesubtask(st)
         end
         if state == "continue" then
           -- Task is in progress and other tasks may continue
         elseif state == "blocksiblings" then
           -- Task is in progress and blocking other sibling tasks (that follow this one)
           break
         elseif state == "blockall" then
           -- Task needs full attention and is blocking all other tasks
           return finished, state
         end
       end 
       -- Do task logic
       
       -- Check if finish conditions have been met
       finished, state = self:check(dt)
       return finished, state  
     end,
  }
  return task
end

taskA = createtask("A")
taskB = createtask("B")
taskC = createtask("C")
taskD = createtask("D")

taskA:addsubtask(taskB)
taskA:addsubtask(taskC)
taskA:act() -->C Inprogress
taskA:act() -->C Finished
taskA:addsubtask(taskD)
taskA:act() -->D Inprogress
taskA:act() -->D Finished
taskA:act() -->B Inprogress
taskA:act() -->B & A Finished
taskA:act() -->A Finished

run   = "run"
pause = "pause"
stop  = "stop"
timer = function(wait) 
 return  {
  call = function(self)
    if self.nexttick >= os.clock() then
      return false  
    else
      print("tick",self.wait)
      self.nexttick = os.clock() + self.wait
      return true
    end  
  end,
  status = run,
  wait = wait or 1,  --period
  nexttick = os.clock()+(wait or 1), 
 }
end

function smaller(a,b)
  return a.nexttick < b.nexttick
end
--inserting towards the end reduces the number of moves in the array
function orderedinsert (array, value, smaller)
  local index = 1
  while smaller(array[index],value) do
    index = index + 1
  end
  table.insert(array,index,value)
end

timers = function()
  t1 = timer(10)
  t2 = timer(7)
  t3 = timer(5)
  t4 = timer(3)
  list = {t1}
  orderedinsert(list,t2,smaller)
  orderedinsert(list,t3,smaller)
  orderedinsert(list,t4,smaller)
  while true do
   for _,v in ipairs(list) do
     if v:call() ~= true then
       break
     else
       table.remove(list,_)
       orderedinsert(list,v,smaller)  
     end
   end
  end
end  

taskA={
  frequency=1,
  nextcall=clock,
  work=function(self) print("taskA",self,self.nextcall) end,
  go=function(self,now) self:work(); self.nextcall = now+self.frequency end,
}
taskB={
  frequency=3,
  nextcall=clock,
  work=function(self) print("taskB",self,self.nextcall) end,
  go=function(self,now) self:work(); self.nextcall = now+self.frequency end,
}

scheduler = {}
scheduler.tasks={}
scheduler.nextwakeup=clock+1000000000
table.insert(scheduler.tasks,taskA)
table.insert(scheduler.tasks,taskB)

scheduler.go = function(self)
    while true do
        local now = clock
        local next = 0
        for k,v in pairs(self.tasks) do
            if now >= v.nextcall then
                v:go(now)
                if self.nextwakeup > v.nextcall then
                    print("set")
                    next = v.nextcall
                end 
            end
        end
        local delta = next-clock 
        wait(delta)
        self.nextwakeup = next
        print(self.nextwakeup)
    end
end

scheduler:go()

_ls={}//localized string table
mt_localizedstring = {
  __tostring = function (self)
    return self[LANG] or self["base"]
  end,
  __index = function (t,k)
    return mt_localizedstring[k]
  end   
}
setmetatable(_ls,mt_localizedstring)

--localized string
function string.localized(s)
    _ls = _ls or {}
    local loc = _ls[s] or {}
    setmetatable(loc,mt_localizedstring)
    loc["base"]=s
    _ls[s]=loc
    return loc
end


l = string.localized
y = l"Yahoo!"
print(y)
y["jp"] = "Yoshi！"
LANG = "jp"
print(y)


curry = function (f,...)
  local vargs = {...}
  local c = function(　)
    f(unpack(vargs))
  end
  return c
end

c = curry(print,1,2,3)
c()

--fixtures
beforetest = function () --setup
  --done before a test
end

aftertest = function() --teardown
  --done after a test
end

beforesuite = function()

end

aftersuite = function()

end

--expected error

--tests should exist in a parallel folder, so all tests can be included or not
--[[
src
   com
      xyz
         SomeClass.java
test
   com
      xyz
         SomeClassTest.java
--]]	

--When a script crashes or a problem is detected by the interpreter, 
--the object is reset to a known state (e.g. the initial state). 
--This means the game can continue without affecting the player’s experience.

--The scripts for the actors are handled similarly. When a problem occurs, 
--the actor is reloaded from the last save, and repositioned in the world. 

--The Sims uses a form of inheritance to help reuse code. This is done according to the file system: the closer towards the root directory the more general the code (e.g. global scripts), and specific objects are in the leaves. 
--This helps create expansion packs, as different directories may override the base file system. Any game with a Quake-like PAK archiving system supports file system extensions, but this needs to be integrated with the scripting engine. 
--The actions possible based on the objects that are available.
--The reward that each action provides to the current actor.
--The distance of the object to the current location.
--The level of need felt by the actor at the time.

--The behavior of the actors in The Sims is very much a by-product of the decision making and the smart objects. As such, they don’t really do much intelligent reasoning. In fact all their plans are “canned,” meaning they are specified manually using scripts.

--fill in the blank stories with actors as slots

function fill(s,values)
  local k,v
  for k,v in pairs(values) do
    s = string.gsub(s,"@"..tostring(k),tostring(v))
  end
  return s
end
print(fill("Hello @name are you @mood today?",{name="Robert",mood="fine"}))

--example for a commandline app
i = 0
while i <2 do
 io.write(">")
 local cmd = io.read()
 i=i+1
 print(cmd)--forward to server
end
　 
--determine sectors where NPCs reside (NPCs register and unregister themselves with sectors)
--Calculate in parallel (OMP) what kind of events have taken place (also who can see who checks)
--These events can be handled by Actors in parallel

--Percentage of change to a file in source control, the lesser the change percentage the more stable(?) that doc/system is
--Steal work in halves (1/2,1/4,1/8,...)

--Page fold that shows the inside of the page!!!
--See screen shot "docs/mom/foldedpage.png"

--pipeline architectures can benefit linearly (almost) from multiprocessors

--use of a bitvector compare to check for interest of a listener for an event
--Use a decorator for stackable counting, just keep one item + decorator 

--non UI -> use case design for controller pattern
--Factory serves as a single interface that manages creators/builders of objects
--Information Expert pattern, centralizing information for increased flexibility
